<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import {
  NButton,
  useMessage,
  useThemeVars,
  NSpin,
  NScrollbar,
  NTree,
  type TreeOption,
  type FormRules,
  type FormInst,
  NForm,
  NFormItem,
  NInput,
  NTreeSelect,
  NRadioGroup,
  NRadioButton,
  NModal,
  NButtonGroup
} from 'naive-ui'
import { sendRequest } from '@/utils/api'
import type { MenuModel } from '@/api/sysMenu'
import type { HttpResponse } from '@/utils/http'
import type { DicTreeModel, DicModel } from '@/api/dic'
import { DicType, MenuTypeCode, Platform } from '@/enums/system'
import ModalCard from '@/components/ModalCard.vue'
import Icons from '@/icons'

const message = useMessage()
const primaryColor = useThemeVars().value.primaryColorHover
const roleLoading = ref(false)
const treeLoading = ref(false)
const formRef = ref<FormInst | null>(null)
const activeId = ref<number | null>(null)
const menuOptions = ref<DicTreeModel[]>([])
const isEdit = ref(false)
const updateLoading = ref(false)
const selectIconVisible = ref(false)
const selectedIconName = ref('')

watch(selectIconVisible, (v) => {
  if (!v) selectedIconName.value = ''
})

const form = ref<
  | (MenuModel & {
      dicType?: number
    })
  | null
>(null)
const nodeProps = ({ option }: { option: TreeOption }) => {
  return {
    onClick() {
      activeId.value = option.id as number
      queryNodeInfo()
    }
  }
}
const formRules: FormRules = {
  menuName: {
    required: true,
    trigger: ['blur'],
    message: '名称不能为空'
  },
  routeUrlDir: {
    required: true,
    trigger: ['blur'],
    message: '路由文件不能为空'
  },
  routeUrl: {
    required: true,
    trigger: ['blur'],
    message: '路由不能为空'
  },
  parentMenuId: {
    required: true,
    type: 'number',
    trigger: ['blur', 'change'],
    message: '上级目录不能为空'
  }
}

// 获取菜单列表
const queryMenuOptions = async () => {
  treeLoading.value = true
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'sysMenu',
    api: 'getTree'
  })
  treeLoading.value = false

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  menuOptions.value = res.data
}

// 获取功能类型
const featureTypeOptions = ref<DicTreeModel[] | undefined>()
const queryFeatureOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: Platform.Parent
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  featureTypeOptions.value = res.data[0]?.children
}

// 获取菜单类型
const isDir = ref(false)
const queryFeatureType = async (menuTypeCode: string) => {
  const [error, res] = await sendRequest<HttpResponse<DicModel>>({
    module: 'dic',
    api: 'infoByCode',
    uri: {
      code: menuTypeCode
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  isDir.value = res.data.dicCode === MenuTypeCode.Dir
}

// 获取菜单详情
const queryNodeInfo = async () => {
  isEdit.value = false
  roleLoading.value = true
  treeLoading.value = true
  const [error, res] = await sendRequest<HttpResponse<MenuModel>>({
    module: 'sysMenu',
    api: 'info',
    uri: {
      id: activeId.value as unknown as string
    }
  })
  roleLoading.value = false
  treeLoading.value = false

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  await queryFeatureType(res.data.menuTypeCode)
  form.value = res.data
  formRef.value?.restoreValidation()
}

const submit = async () => {
  formRef.value?.validate(async (err) => {
    if (err) return

    updateLoading.value = true
    const [error, res] = await sendRequest({
      module: 'sysMenu',
      api: 'update',
      override: {
        data: form.value
      }
    })
    updateLoading.value = false

    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    message.success(res.msg)
    queryMenuOptions()
    queryNodeInfo()
  })
}

onMounted(async () => {
  queryMenuOptions()
  queryFeatureOptions()
})
</script>

<template>
  <div class="feature">
    <div class="feature-content">
      <div class="card edit">
        <div class="card__title">功能清单</div>
        <NSpin
          :show="treeLoading"
          class="card__spin"
        >
          <NScrollbar>
            <NTree
              :node-props="nodeProps"
              :data="menuOptions"
              key-field="id"
              default-expand-all
              label-field="name"
              block-line
            />
          </NScrollbar>
        </NSpin>
      </div>
      <div
        class="card edit"
        v-if="form"
      >
        <div class="card__title">详细信息</div>
        <NSpin
          :show="roleLoading"
          class="card__spin"
        >
          <NScrollbar style="height: calc(100% - 60px)">
            <NForm
              :disabled="!isEdit"
              :model="form"
              :rules="formRules"
              ref="formRef"
              label-placement="left"
              label-width="80"
              size="small"
              style="padding: 15px"
            >
              <NFormItem
                label="功能类型"
                path="menuTypeCode"
              >
                <NTreeSelect
                  disabled
                  v-model:value="form.menuTypeCode"
                  :options="featureTypeOptions"
                  size="small"
                  key-field="code"
                  label-field="name"
                />
              </NFormItem>
              <NFormItem
                label="名称"
                path="menuName"
              >
                <NInput v-model:value="form.menuName" />
              </NFormItem>
              <NFormItem
                label="配置"
                path="configuration"
              >
                <NInput
                  v-model:value="form.configuration"
                  type="textarea"
                />
              </NFormItem>
              <template v-if="!isDir">
                <NFormItem
                  label="路由文件"
                  path="routeUrlDir"
                >
                  <NInput v-model:value="form.routeUrlDir" />
                </NFormItem>
                <NFormItem
                  label="路由"
                  path="routeUrl"
                >
                  <NInput v-model:value="form.routeUrl" />
                </NFormItem>
              </template>
              <NFormItem
                label="上级目录"
                path="parentMenuId"
              >
                <NTreeSelect
                  disabled
                  v-model:value="form.parentMenuId"
                  :options="menuOptions"
                  size="small"
                  key-field="id"
                  :placeholder="form.parentMenuId === 0 ? 'ROOT' : '请选择'"
                  label-field="name"
                />
              </NFormItem>
              <NFormItem
                label="排序号"
                path="sortIndex"
              >
                <NInput v-model:value="form.sortIndex" />
              </NFormItem>
              <NFormItem
                label="图标"
                path="iconUrl"
              >
                <NInput
                  v-model:value="form.iconUrl"
                  placeholder="请选择"
                  disabled
                >
                  <template #suffix>
                    <NButtonGroup>
                      <NButton
                        v-show="isEdit"
                        size="tiny"
                        type="primary"
                        @click="selectIconVisible = true"
                      >
                        点击选择
                      </NButton>
                      <NButton
                        v-show="isEdit"
                        size="tiny"
                        color="#fbc531"
                        @click=";[(form!.iconUrl = ''), (selectedIconName = '')]"
                      >
                        清除
                      </NButton>
                    </NButtonGroup>
                  </template>
                </NInput>
              </NFormItem>
              <NFormItem
                v-show="form.dicType === DicType.Custom"
                label="状态"
                path="menuStatus"
              >
                <NRadioGroup v-model:value="form.menuStatus">
                  <NRadioButton
                    :value="1"
                    label="正常"
                  />
                  <NRadioButton
                    :value="0"
                    label="禁用"
                  />
                </NRadioGroup>
              </NFormItem>
            </NForm>
          </NScrollbar>

          <NButton
            v-if="!isEdit"
            type="primary"
            round
            :disabled="roleLoading"
            style="margin: 13px 15px"
            @click="isEdit = true"
          >
            修改
          </NButton>
          <NButton
            v-else
            type="primary"
            round
            :loading="updateLoading"
            :disabled="updateLoading"
            style="margin: 13px 15px"
            @click="submit"
          >
            保存
          </NButton>
        </NSpin>
      </div>
    </div>
  </div>

  <NModal :auto-focus="false" v-model:show="selectIconVisible">
    <ModalCard
      title="选择图标"
      action
      @close="selectIconVisible = false"
      @submit="selectIconVisible = false"
    >
      <div class="select-icon">
        <span
          v-for="icon in Icons"
          :key="icon.name"
          :class="(selectedIconName === icon.name || form!.iconUrl === icon.name) && 'active'"
        >
          <component
            :is="icon.component"
            @click=";[(form!.iconUrl = icon.name), (selectedIconName = icon.name)]"
          />
        </span>
      </div>
    </ModalCard>
  </NModal>
</template>

<style lang="scss" scoped>
:global(.select-icon) {
  display: grid;
  grid-template-columns: repeat(8, auto);
  gap: 10px;
  padding: 20rem;
  margin: 20rem 20rem 0;
  background-color: #ebeceb;
}
:global(.select-icon > span.active) {
  color: #5fb17f;
}
:global(.select-icon > span:hover) {
  color: #5fb17f;
}
:global(.select-icon > span) {
  cursor: pointer;
}

.feature {
  width: 100%;
  height: 100%;
  padding: 20rem;

  .feature-content {
    display: flex;
    gap: 0 30px;
    height: 100%;
    padding: 20rem;
    background-color: #ebeceb;
  }

  .card {
    height: 100%;
    width: 30%;
    min-width: 400px;

    &__title {
      display: flex;
      align-items: center;
      height: 40px;
      padding: 0 1em;
      font-size: 18px;
      font-weight: 600;
      color: #fff;
      background-color: v-bind(primaryColor);
      border-radius: 3px 3px 0 0;
    }

    &__spin {
      height: calc(100% - 40px);
      border: 1px solid #d1d8e0;
      border-top: none;
      border-radius: 0 0 3px 3px;

      & :deep(.n-spin-content) {
        height: 100%;
      }
    }

    &:nth-child(2) {
      flex: 1;
    }
  }
}
</style>
